<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Virtual List</title>
		<style>
			#container {
				width: 300px;
				overflow-y: auto;
				position: relative;
				border: 1px solid #ccc;
			}

			.item {
				height: 50px;
				width: 100%;
				box-sizing: border-box;
				border-bottom: 1px solid #eee;
				padding: 5px;
			}

			.spacer {
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
			}

			.loading {
				display: flex;
				justify-content: center;
				align-items: center;
				height: 100%;
				font-size: 20px;
			}
		</style>
	</head>

	<body>
		<div id="container">
			<div id="list"></div>
			<div id="spacer"></div>
		</div>
		<div id="loading" class="loading">Loading...</div>

		<script>
			const totalItems = 10000 // 数据总量
			const itemHeight = 50 // 每个列表项的高度
			const containerHeight = 600 // 容器的高度
			const visibleCount = Math.ceil(containerHeight / itemHeight) // 计算可见项目数

			const container = document.getElementById('container')
			container.style.height = `${containerHeight}px` // 设置容器的高度
			const list = document.getElementById('list')
			const spacer = document.getElementById('spacer')
			const loading = document.getElementById('loading')

			// 假设数据已经生成
			const data = Array.from(
				{ length: totalItems },
				(_, i) => `Item ${i + 1}`
			)

			spacer.style.height = `${(totalItems - 6) * itemHeight}px` // 设置占位元素的高度

			function renderVisibleItems() {
				console.log('renderVisibleItems')
				const scrollTop = container.scrollTop // 获取滚动位置
				const startIndex = Math.floor(scrollTop / itemHeight) // 当前视口内第一个可见元素的索引
				const endIndex = Math.min(
					startIndex + visibleCount + 1,
					totalItems
				) // 视口内最后一个可见元素的索引

				list.style.transform = `translateY(${
					startIndex * itemHeight
				}px)` // 设置列表的偏移
				list.innerHTML = '' // 清空列表

				// 渲染可见的项目
				for (let i = startIndex; i < endIndex; i++) {
					const item = document.createElement('div')
					item.className = 'item'
					item.textContent = data[i]
					list.appendChild(item)
				}
			}

			// 初始渲染
			loading.style.display = 'block' // 显示加载指示器
			setTimeout(() => {
				renderVisibleItems()
				loading.style.display = 'none' // 隐藏加载指示器
			}, 1000) // 假设数据加载需要1秒钟

			// 节流监听滚动事件
			container.addEventListener('scroll', renderVisibleItems)
			function throttle(func, delay) {
				let timer = null
				return function () {
					if (timer) return
					timer = setTimeout(() => {
						func.apply(this, arguments)
						timer = null
					}, 100)
				}
			}
		</script>
	</body>
</html>
